﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Net;
using System.IO;
using System.Windows;
using Kirishima16.Net.Twitter.Scraping;

using Res = WasaWasa.Properties.Resources;
using System.Threading;
using Kirishima16.Net.Twitter;

namespace WasaWasa
{
    partial class MainWindow
    {
        private const string ApiPathUpdateStatus = "/statuses/update.json";
        private const string ApiPathUpdateChannel = "/channel_message/update.json";
        private const string JaikuApiPathJson = "/json";

        private const string TwitterApiHost = "twitter.com";
        private const string Mogo2ApiHost = "api.mogo2.jp";
        private const string JaikuApiHost = "api.jaiku.com";

        private const string PostContentType = "application/x-www-form-urlencoded;charset=utf-8";

        private ReplyType replyType;
        private TimelineBundle replyTimeline;
        private StatusClass replyStatus;
        private string replyUser;

        private TwitterClient twClient;

        [Flags]
        private enum ReplyType
        {
            NotReply = 0,
            General = 1,
            Channel = 2,
            Status = 4,
            User = 8,
            ChannelAndUser = 10,
        }

        private void InitializeTwitter()
        {
            if (def.UseCrossPostToTwitter)
            {
                twClient = new TwitterClient();
                if (twClient.Login(def.TwitterUserName, DESStringCrypto.DecryptString(def.TwitterPassword))== LoginResult.Success)
                {
                    AppendLogText(Res.ToTwitter + Res.OperationLoginSucceed);
                }
                else
                {
                    AppendLogText(Res.ToTwitter + Res.OperationLoginFailed);
                    AppendLogText(Res.OfTwitter + Res.ErrorInvalidAccountSettings);
                }
            }
        }

        private void FinalizeTwitter()
        {
            if (twClient != null && twClient.IsLogined)
            {
                if (twClient.Logout() == LogoutResult.Success)
                {
                    AppendLogText(Res.OfTwitter + Res.OperationLogoutSuccess);
                }
                else
                {
                    AppendLogText(Res.OfTwitter + Res.OperationLogoutFailed);
                }
            }
        }

        /// <summary>
        /// ヒトコトを更新します。
        /// </summary>
        private void UpdateStatus()
        {
            AppendLogText(Res.MessageUpdateStatus);

            if (replyType == ReplyType.NotReply)
            {
                replyTimeline = tabsTimeline.SelectedItem as TimelineBundle;
                if (replyTimeline.Type == TimelineType.Channel)
                    replyType |= ReplyType.Channel;
                else
                    replyType |= ReplyType.General;
            }

            UriBuilder ub = null;
            byte[] postbin = null;
            string status = txtUpdate.Text;

            if ((replyType & ReplyType.User) == ReplyType.User)
            {
                status = "@" + replyUser + " " + status;
            }
            if ((replyType & ReplyType.Channel) == ReplyType.Channel)
            {
                ub = new UriBuilder(Uri.UriSchemeHttp, ApiHost, ApiPort, ApiPathUpdateChannel, string.Format("?name_en={0}", replyTimeline.Tags["NameEn"]));
                postbin = Encoding.ASCII.GetBytes(string.Format("source={0}&body={1}",
                             HttpUtility.UrlEncode(Res.StringSourceName, Encoding.UTF8),
                             HttpUtility.UrlEncode(status, Encoding.UTF8)));
            }
            else
            {
                ub = new UriBuilder(Uri.UriSchemeHttp, ApiHost, ApiPort, ApiPathUpdateStatus);
                postbin = Encoding.ASCII.GetBytes(string.Format("source={0}&status={1}",
                             HttpUtility.UrlEncode(Res.StringSourceName, Encoding.UTF8),
                             HttpUtility.UrlEncode(status, Encoding.UTF8)) +
                             (replyStatus != null ? string.Format("&reply_status_rid={0}", replyStatus.Rid) : ""));
            }

            if (true)
            {
                HttpWebRequest wreq = WebRequest.Create(ub.Uri) as HttpWebRequest;
                wreq.Method = WebRequestMethods.Http.Post;
                wreq.ContentLength = postbin.Length;
                wreq.ContentType = PostContentType;
                if (!SetWebRequestOptions(wreq)) return;
                IAsyncResult oar = wreq.BeginGetRequestStream(new AsyncCallback(delegate(IAsyncResult ar)
                {
                    using (Stream spost = wreq.EndGetRequestStream(ar))
                    {
                        spost.Write(postbin, 0, postbin.Length);
                    }

                    wreq.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult ar2)
                    {
                        try
                        {
                            using (HttpWebResponse wres = wreq.EndGetResponse(ar2) as HttpWebResponse)
                            {
                                AppendLogText(Res.OperationUpdateWassrStatus + Enum.GetName(typeof(HttpStatusCode), wres.StatusCode));
                                Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
                                {
                                    if (def.IsLoadTimelineAfterPost)
                                    {
                                        if (replyTimeline.Type == TimelineType.Channel)
                                        {
                                            LoadTimeline(replyTimeline);
                                        }
                                        else
                                        {
                                            LoadTimeline(timelines[0]);
                                        }
                                    }
                                    txtUpdate.Text = "";
                                    ClearReplyInfo();
                                }));
                            }
                        }
                        catch (WebException ex)
                        {
                            AppendLogText(Res.OperationUpdateWassrStatus + Enum.GetName(typeof(HttpStatusCode), (ex.Response as HttpWebResponse).StatusCode));
                            return;
                        }
                    }), null);
                }), null);
                ThreadPool.RegisterWaitForSingleObject(oar.AsyncWaitHandle, new WaitOrTimerCallback(TimeOutCallback), new object[] { wreq, Res.OperationUpdateWassrStatus }, 30000, true);
            }

            //Twitterにクロスポスト
            if (def.UseCrossPostToTwitter && IsUpdateToCrossPost(status) && twClient.IsLogined)
            {
                try
                {
                    if (twClient.UpdateStatus(status) != null)
                    {
                        AppendLogText(Res.OfTwitter + Res.OperationCrossPost + "成功");
                    }
                    else
                    {
                        AppendLogText(Res.OfTwitter + Res.OperationCrossPost + "失敗:POST規制?");
                    }
                }
                catch (HttpException ex)
                {
                    AppendLogText(Res.OfTwitter + Res.OperationCrossPost + "失敗:" + ex.Message);
                }
            }
            //while (def.UseCrossPostToTwitter && IsUpdateToCrossPost(status))
            //{
            //    UriBuilder xpub = new UriBuilder(Uri.UriSchemeHttp, TwitterApiHost, ApiPort, ApiPathUpdateStatus);
            //    byte[] xppostbin = Encoding.ASCII.GetBytes(
            //        string.Format("status={0}", HttpUtility.UrlEncode(status, Encoding.UTF8)));
            //    HttpWebRequest xpwreq = WebRequest.Create(xpub.Uri) as HttpWebRequest;
            //    xpwreq.Method = WebRequestMethods.Http.Post;
            //    xpwreq.ContentLength = xppostbin.Length;
            //    xpwreq.ContentType = PostContentType;
            //    if (!SetWebRequestProxy(xpwreq)) return;
            //    if (!SetWebRequestUserAgent(xpwreq)) return;
            //    try
            //    {
            //        xpwreq.Credentials = new NetworkCredential(def.TwitterUserName, DESStringCrypto.DecryptString(def.TwitterPassword));
            //    }
            //    catch
            //    {
            //        AppendLogText(Res.OfTwitter + Res.ErrorInvalidAccountSettings);
            //        break;
            //    }
            //    IAsyncResult oar = xpwreq.BeginGetRequestStream(new AsyncCallback(delegate(IAsyncResult ar)
            //    {
            //        using (Stream spost = xpwreq.EndGetRequestStream(ar))
            //        {
            //            spost.Write(xppostbin, 0, xppostbin.Length);
            //        }

            //        xpwreq.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult ar2)
            //        {
            //            try
            //            {
            //                using (HttpWebResponse wres = xpwreq.EndGetResponse(ar2) as HttpWebResponse)
            //                {
            //                    AppendLogText(Res.OfTwitter + Res.OperationCrossPost + Enum.GetName(typeof(HttpStatusCode), wres.StatusCode));
            //                }
            //            }
            //            catch (WebException ex)
            //            {
            //                AppendLogText(Res.OfTwitter + Res.OperationCrossPost + Enum.GetName(typeof(HttpStatusCode), (ex.Response as HttpWebResponse).StatusCode));
            //            }
            //        }), null);
            //    }), null);
            //    ThreadPool.RegisterWaitForSingleObject(oar.AsyncWaitHandle, new WaitOrTimerCallback(TimeOutCallback), new object[] { xpwreq, Res.OfTwitter + Res.OperationCrossPost }, 30000, true);

            //    break;
            //}

            //もごもごにクロスポスト
            while (def.UseCrossPostToMogo2 && IsUpdateToCrossPost(status))
            {
                UriBuilder xpub = new UriBuilder(Uri.UriSchemeHttp, Mogo2ApiHost, ApiPort, ApiPathUpdateStatus);
                byte[] xppostbin = Encoding.ASCII.GetBytes(
                    string.Format("status={0}", HttpUtility.UrlEncode(status, Encoding.UTF8)));
                HttpWebRequest xpwreq = WebRequest.Create(xpub.Uri) as HttpWebRequest;
                xpwreq.Method = WebRequestMethods.Http.Post;
                xpwreq.ContentLength = xppostbin.Length;
                xpwreq.ContentType = PostContentType;
                if (!SetWebRequestProxy(xpwreq)) return;
                if (!SetWebRequestUserAgent(xpwreq)) return;
                try
                {
                    xpwreq.Credentials = new NetworkCredential(def.Mogo2UserName, DESStringCrypto.DecryptString(def.Mogo2Password));
                }
                catch
                {
                    AppendLogText(Res.OfMogo2 + Res.ErrorInvalidAccountSettings);
                    break;
                }
                IAsyncResult oar = xpwreq.BeginGetRequestStream(new AsyncCallback(delegate(IAsyncResult ar)
                {
                    using (Stream spost = xpwreq.EndGetRequestStream(ar))
                    {
                        spost.Write(xppostbin, 0, xppostbin.Length);
                    }

                    xpwreq.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult ar2)
                    {
                        try
                        {
                            using (HttpWebResponse wres = xpwreq.EndGetResponse(ar2) as HttpWebResponse)
                            {
                                AppendLogText(Res.OfMogo2 + Res.OperationCrossPost + Enum.GetName(typeof(HttpStatusCode), wres.StatusCode));
                            }
                        }
                        catch (WebException ex)
                        {
                            AppendLogText(Res.OfMogo2 + Res.OperationCrossPost + Enum.GetName(typeof(HttpStatusCode), (ex.Response as HttpWebResponse).StatusCode));
                        }
                    }), null);
                }), null);
                ThreadPool.RegisterWaitForSingleObject(oar.AsyncWaitHandle, new WaitOrTimerCallback(TimeOutCallback), new object[] { xpwreq, Res.OfMogo2 + Res.OperationCrossPost }, 30000, true);

                break;
            }

            //Jaikuにクロスポスト
            while (def.UseCrossPostToJaiku && IsUpdateToCrossPost(status))
            {
                UriBuilder xpub = new UriBuilder(Uri.UriSchemeHttp, JaikuApiHost, ApiPort, JaikuApiPathJson);
                string password = null;
                try
                {
                    password = DESStringCrypto.DecryptString(def.JaikuPassword);
                }
                catch
                {
                    AppendLogText(Res.OfJaiku + Res.ErrorInvalidAccountSettings);
                    break;
                }
                byte[] xppostbin = Encoding.ASCII.GetBytes(
                    string.Format("user={0}&personal_key={1}&method=presence.send&message={2}",
                    def.JaikuUserName, password, HttpUtility.UrlEncode(status, Encoding.UTF8)));
                HttpWebRequest xpwreq = WebRequest.Create(xpub.Uri) as HttpWebRequest;
                xpwreq.Method = WebRequestMethods.Http.Post;
                xpwreq.ContentLength = xppostbin.Length;
                xpwreq.ContentType = PostContentType;
                if (!SetWebRequestProxy(xpwreq)) return;
                if (!SetWebRequestUserAgent(xpwreq)) return;
                IAsyncResult oar = xpwreq.BeginGetRequestStream(new AsyncCallback(delegate(IAsyncResult ar)
                {
                    using (Stream spost = xpwreq.EndGetRequestStream(ar))
                    {
                        spost.Write(xppostbin, 0, xppostbin.Length);
                    }

                    xpwreq.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult ar2)
                    {
                        try
                        {
                            using (HttpWebResponse wres = xpwreq.EndGetResponse(ar2) as HttpWebResponse)
                            {
                                AppendLogText(Res.OfJaiku + Res.OperationCrossPost + Enum.GetName(typeof(HttpStatusCode), wres.StatusCode));
                            }
                        }
                        catch (WebException ex)
                        {
                            AppendLogText(Res.OfJaiku + Res.OperationCrossPost + Enum.GetName(typeof(HttpStatusCode), (ex.Response as HttpWebResponse).StatusCode));
                        }
                    }), null);
                }), null);
                ThreadPool.RegisterWaitForSingleObject(oar.AsyncWaitHandle, new WaitOrTimerCallback(TimeOutCallback), new object[] { xpwreq, Res.OfJaiku + Res.OperationCrossPost }, 30000, true);

                break;
            }
        }

        private bool IsUpdateToCrossPost(string status)
        {
            return (def.IsCrossPostUpdateToChannel || (replyType & ReplyType.Channel) != ReplyType.Channel)
                && (def.IsCrossPostReplyToStatus || (replyType & ReplyType.Status) != ReplyType.Status)
                && (def.IsCrossPostReplyToUser || !status.StartsWith("@") && status.Length <= 140);
        }

        private void ClearReplyInfo()
        {
            replyType = ReplyType.NotReply;
            replyTimeline = null;
            replyStatus = null;
            replyUser = null;
            txtReplyTarget.Text = null;
            txtReplyTarget.ToolTip = null;
        }
    }
}
